package cn.sylinx.hbatis.ext.common.repository;

import java.math.BigInteger;
import java.util.List;

import cn.sylinx.hbatis.db.common.Callable;
import cn.sylinx.hbatis.db.common.ITransaction;
import cn.sylinx.hbatis.db.common.Record;
import cn.sylinx.hbatis.db.dialect.Dialect;
import cn.sylinx.hbatis.db.mapper.ModelBuilder;
import cn.sylinx.hbatis.db.mapper.QueryMapper;
import cn.sylinx.hbatis.exception.HbatisException;
import cn.sylinx.hbatis.ext.common.spi.HbatisServiceManager;
import cn.sylinx.hbatis.ext.model.BaseModel;
import cn.sylinx.hbatis.log.GLog;

public class CommonRepositoryImpl implements CommonRepository {

	private String datasourceName;

	public CommonRepositoryImpl() {

	}

	public CommonRepositoryImpl(String datasourceName) {
		this.datasourceName = datasourceName;
	}

	@Override
	public String getDatabase() {

		if (datasourceName == null) {
			initDatabaseInner();
		}

		return datasourceName;
	}

	@Override
	public Dialect getDialect() {
		return HbatisServiceManager.getHbatisService().use(getDatabase()).getDialect();
	}

	private synchronized void initDatabaseInner() {

		if (datasourceName == null) {
			datasourceName = HbatisServiceManager.getHbatisService().getDatasourceName();
		}
	}

	@Override
	public <T> T call(Callable<T> callable) {
		return HbatisServiceManager.getHbatisService().use(getDatabase()).call(callable);
	}

	@Override
	public boolean existTable(String schema, String table) {
		return HbatisServiceManager.getHbatisService().use(getDatabase()).existTable(schema, table);
	}

	@Override
	public boolean existTableColumn(String schema, String table, String column) {
		return HbatisServiceManager.getHbatisService().use(getDatabase()).existTableColumn(schema, table, column);
	}

	@Override
	public List<Record> queryRecordsWithCache(String sql, Object... params) {
		return HbatisServiceManager.getHbatisService().use(getDatabase()).withCache().queryRecords(sql, params);
	}

	@Override
	public List<Record> queryRecordsWithCache(String sql) {
		return HbatisServiceManager.getHbatisService().use(getDatabase()).withCache().queryRecords(sql);
	}

	@Override
	public Record queryRecordWithCache(String sql, Object... params) {
		return HbatisServiceManager.getHbatisService().use(getDatabase()).withCache().queryFirstRecord(sql, params);
	}

	@Override
	public Record queryRecordWithCache(String sql) {
		return HbatisServiceManager.getHbatisService().use(getDatabase()).withCache().queryFirstRecord(sql);
	}

	@Override
	public boolean transaction(ITransaction transactions) {
		return HbatisServiceManager.getHbatisService().use(getDatabase()).transaction(transactions);
	}

	@Override
	public <T> List<T> queryObject(String sql, Class<T> clazz, Object... params) {
		return HbatisServiceManager.getHbatisService().use(getDatabase()).queryObject(sql, clazz, params);
	}

	@Override
	public <T> T queryFirstObject(String sql, Class<T> clazz, Object... params) {
		return HbatisServiceManager.getHbatisService().use(getDatabase()).queryFirstObject(sql, clazz, params);
	}

	@Override
	public int update(String nativeSql, Object... params) {
		return HbatisServiceManager.getHbatisService().use(getDatabase()).update(nativeSql, params);
	}

	@Override
	public List<Record> queryRecords(String sql, Object... params) {
		return HbatisServiceManager.getHbatisService().use(getDatabase()).queryRecords(sql, params);
	}

	@Override
	public List<Record> queryRecords(String sql) {
		return HbatisServiceManager.getHbatisService().use(getDatabase()).queryRecords(sql);
	}

	@Override
	public Record queryRecord(String sql, Object... params) {
		return HbatisServiceManager.getHbatisService().use(getDatabase()).queryFirstRecord(sql, params);
	}

	@Override
	public Record queryRecord(String sql) {

		return HbatisServiceManager.getHbatisService().use(getDatabase()).queryFirstRecord(sql);
	}

	@Override
	public <T> List<T> queryListWithCache(Class<T> clz) {

		String table = ModelBuilder.getModelTable(clz);
		if (table == null) {
			throw new HbatisException("对象没有Table注解");
		}
		String sql = "select * from " + table;
		QueryMapper<T> mapper = ModelBuilder.buildQueryMapper(clz);
		return HbatisServiceManager.getHbatisService().use(getDatabase()).withCache().query(sql, mapper);
	}

	@Override
	public <T> List<T> queryListWithCache(String nativeSql, Class<T> clz, Object... params) {

		QueryMapper<T> mapper = ModelBuilder.buildQueryMapper(clz);
		return HbatisServiceManager.getHbatisService().use(getDatabase()).withCache().query(nativeSql, mapper, params);
	}

	@Override
	public <T> List<T> queryList(Class<T> clz) {

		String table = ModelBuilder.getModelTable(clz);
		if (table == null) {
			throw new HbatisException("对象没有Table注解");
		}
		String sql = "select * from " + table;
		QueryMapper<T> mapper = ModelBuilder.buildQueryMapper(clz);
		return HbatisServiceManager.getHbatisService().use(getDatabase()).query(sql, mapper);
	}

	@Override
	public <T> List<T> queryList(String nativeSql, Class<T> clz, Object... params) {

		QueryMapper<T> mapper = ModelBuilder.buildQueryMapper(clz);
		return HbatisServiceManager.getHbatisService().use(getDatabase()).query(nativeSql, mapper, params);
	}

	@Override
	public <T extends BaseModel> int update(T t) {
		return HbatisServiceManager.getHbatisService().use(getDatabase()).update(t);
	}

	@Override
	public <T extends BaseModel> int delete(T t) {
		return HbatisServiceManager.getHbatisService().use(getDatabase()).delete(t);
	}

	@Override
	public <T extends BaseModel> int delete(BigInteger id, Class<T> clz) {
		String table = ModelBuilder.getModelTable(clz);
		if (table == null) {
			throw new HbatisException("对象没有Table注解");
		}
		String sql = "delete from " + table + " where id = ?";
		return HbatisServiceManager.getHbatisService().use(getDatabase()).update(sql, id);
	}

	@Override
	public <T extends BaseModel> T save(T t) {

		if (t == null) {
			throw new HbatisException("object t is null");
		}

		Object pk = HbatisServiceManager.getHbatisService().use(getDatabase()).save(t);
		if (pk != null) {
			if (t.getId() == null && (pk instanceof Number)) {
				t.setId(new BigInteger(pk.toString()));
			}
		}

		return t;
	}

	@Override
	public Object insert(String insertSql, Object... params) {
		return HbatisServiceManager.getHbatisService().use(getDatabase()).save(insertSql, params);
	}

	@Override
	public <T extends BaseModel> boolean saveNoPk(T t) {

		if (t == null) {
			throw new HbatisException("object t is null");
		}

		try {
			Object pk = HbatisServiceManager.getHbatisService().use(getDatabase()).save(t);
			GLog.info("save with pk:{}", pk);
		} catch (Exception e) {
			GLog.error("save error", e);
			return false;
		}

		return true;
	}

	@Override
	public <T> boolean saveObjectNoPk(T t) {

		if (t == null) {
			throw new HbatisException("object t is null");
		}

		try {
			Object pk = HbatisServiceManager.getHbatisService().use(getDatabase()).save(t);
			GLog.info("save with pk:{}", pk);
		} catch (Exception e) {
			GLog.error("save error", e);
			return false;
		}

		return true;
	}

	@Override
	public <T> Object saveObject(T t) {

		if (t == null) {
			throw new HbatisException("object t is null");
		}

		Object pk = HbatisServiceManager.getHbatisService().use(getDatabase()).save(t);
		return pk;
	}

	@Override
	public boolean executeLargeUpdate(final List<String> exeSqlList) {
		return HbatisServiceManager.getHbatisService().use(getDatabase()).executeLargeUpdate(exeSqlList);
	}

	@Override
	public int[] batch(List<String> sql) {
		return HbatisServiceManager.getHbatisService().batch(sql);
	}

	@Override
	public int[] batch(String sql, Object[][] params) {
		return HbatisServiceManager.getHbatisService().batch(sql, params);
	}

	@Override
	public int[] batch(String sql, Object[][] params, int batchSize) {
		return HbatisServiceManager.getHbatisService().batch(sql, params, batchSize);
	}

	@Override
	public int[] batch(List<String> sqlList, int batchSize) {
		return HbatisServiceManager.getHbatisService().batch(sqlList, batchSize); 
	}
	
}
